/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package DbPort;

import DataTypes.AutoDiaryDataTypes.AmbiAct;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author thang
 */
public class DataWindowManager {
    private static int windowWeight = 0;
    private static long windowTime = 0; // latest time in a window
    private static String device_id = autodiaryserver.Declare.DEVICE_ID;
    private static int      maxWeight = autodiaryserver.Declare.WINDOW_SIZE; // remember to set violation less than 5 or chang this value
    //private static int      slides = 3;
    

    // ambiguous literal is activity (code)
    //private static String[] ambiLiterals = {"code"};
    private static DataTypes.AutoDiaryDataTypes.WeightMatrix wMatrix = new DataTypes.AutoDiaryDataTypes.WeightMatrix();
    
    
    
    public static void insertData( List<AmbiAct> al){

        if ( al == null ) { return; }        

        // get next window index
        int nextIndex = getNextIndex(device_id);
        
        // if over full then clear window, by sliding window size, this case should not happend
        // remember, index start from 0 to WINDOW_SIZE - 1
        //if ( nextIndex > autodiaryserver.Declare.WINDOW_SIZE ) { 
            // empty window then return
        //    slideWindow(autodiaryserver.Declare.WINDOW_SIZE);
        //    return; 
        //}
        
        // insert answer set to data window (matrix)
        for ( AmbiAct a: al) {
            a.setWindowIndex(nextIndex);
            DataReceiver.receiveData(a);
        }

        // if fully loaded then start reasoning by:
        // calculate weight function then call window reasoning with paramater:
        // array of ambiLiterals with their weight, totalWeight, and window time (= max(time) in window)
        
        // window index start from 1
        if ( nextIndex == autodiaryserver.Declare.WINDOW_SIZE ){
            fillWeightMatrix();
            fillWindowWeight();
            fillWindowTime();
            fillDeviceId();
            reasoner.WindowReasoner.reasoning(wMatrix);
            //slideWindow(slides);
        }
    }
    
    public static void fillDeviceId(){
        wMatrix.device_id = device_id;
    }

    /*
     * - For the device_id:
     * - Delete literal have window_index < window_size - slides
     * - update window_index = window_index - ( window_size - slides )
     */
    public static void slideWindow(int slides){
        
        ResultSet rs = null;
        PreparedStatement ps = null;

        try {        
            // get type id 
            ps = Declare.mCon.prepareStatement("delete from d_actWindow where device_id = ? and window_index <= ?");
            ps.setString(1, device_id);
            ps.setInt( 2, slides );
            ps.executeUpdate();

            ps.close();
            ps = Declare.mCon.prepareStatement("update d_actWindow set window_index = window_index - ? where device_id = ?");
            ps.setInt( 1, slides );
            ps.setString(2, device_id);
            ps.executeUpdate();
                    
        } catch (SQLException ex) {
            Logger.getLogger(DataReceiver.class.getName()).log(Level.SEVERE, null, ex);
        } finally{ 
            if (rs != null) { try { rs.close(); } catch (SQLException ex) {}}  
            if (ps != null) { try { ps.close(); } catch (SQLException ex) {}}  
        }        
       
    }
    
    /*
     * perform weight function for each literal.
     * weight of a window is sum of all weights of every literal
     */
    public static void fillWindowWeight(){
        
        ResultSet rs = null;
        PreparedStatement ps = null;

        try {        
            // get type id 
            //ps = Declare.mCon.prepareStatement("select sum(w) from (select window_index, (? - weight) as w from d_actWindow where device_id = ? group by window_index) a");
            ps = Declare.mCon.prepareStatement("select sum(? - weight) from d_actWindow where device_id = ?");
            ps.setInt( 1, maxWeight );
            ps.setString( 2, device_id );
            rs = ps.executeQuery();
            
            if (rs.first()){
                wMatrix.windowWeight = rs.getInt(1);
            }

        } catch (SQLException ex) {
            Logger.getLogger(DataReceiver.class.getName()).log(Level.SEVERE, null, ex);
        } finally{ 
            if (rs != null) { try { rs.close(); } catch (SQLException ex) {}}  
            if (ps != null) { try { ps.close(); } catch (SQLException ex) {}}  
        }        

    }

    public static void fillWindowTime(){
        ResultSet rs = null;
        PreparedStatement ps = null;

        try {        
            // get type id 
            ps = Declare.mCon.prepareStatement("select max(time) from d_actWindow where device_id = ?");
            ps.setString( 1, device_id );
            rs = ps.executeQuery();
            
            if (rs.first()){
                wMatrix.time = rs.getLong(1);
            }

        } catch (SQLException ex) {
            Logger.getLogger(DataReceiver.class.getName()).log(Level.SEVERE, null, ex);
        } finally{ 
            if (rs != null) { try { rs.close(); } catch (SQLException ex) {}}  
            if (ps != null) { try { ps.close(); } catch (SQLException ex) {}}  
        }        
        //return result;
    }
    
    public static void fillWeightMatrix(){
        
        ResultSet rs = null;
        PreparedStatement ps = null;
        
        // reset weightMatrix
        if ( wMatrix.matrix == null ) {
            wMatrix.matrix = new ArrayList<DataTypes.AutoDiaryDataTypes.AmbiLiteral>();
        } else {
            wMatrix.matrix.clear();
        }
            
        try {        
            // get type id 
            ps = Declare.mCon.prepareStatement("select code, sum(? - weight) from d_actWindow where device_id = ? group by code");
            ps.setInt( 1, maxWeight );
            ps.setString(2, device_id);
            rs = ps.executeQuery();
            
            if (rs.first()){
                while ( !(rs.isAfterLast()) ) {
                    DataTypes.AutoDiaryDataTypes.AmbiLiteral al = new DataTypes.AutoDiaryDataTypes.AmbiLiteral();
                    al.code = rs.getString(1);
                    al.weight = rs.getInt(2);
                    wMatrix.matrix.add(al);
                    rs.next();
                }
            }

        } catch (SQLException ex) {
            Logger.getLogger(DataReceiver.class.getName()).log(Level.SEVERE, null, ex);
        } finally{ 
            if (rs != null) { try { rs.close(); } catch (SQLException ex) {}}  
            if (ps != null) { try { ps.close(); } catch (SQLException ex) {}}  
        }        

    }
            
    /*
     * get next window index for new sample
     * 
     */
    public static int getNextIndex(String device_id){
        int nextIndex = 1;
        ResultSet rs = null;
        PreparedStatement ps = null;

        try {        
            // get type id 
            ps = Declare.mCon.prepareStatement("select max(window_index) from d_actWindow where device_id = ?");
            ps.setString( 1, device_id );
            rs = ps.executeQuery();

            if (rs.first()){
                nextIndex = rs.getInt(1) + 1;
            }

        } catch (SQLException ex) {
            Logger.getLogger(DataReceiver.class.getName()).log(Level.SEVERE, null, ex);
        } finally{ 
            if (rs != null) { try { rs.close(); } catch (SQLException ex) {}}  
            if (ps != null) { try { ps.close(); } catch (SQLException ex) {}}  
        }

        return nextIndex;
    }
    
}
